# 这个类是用来对Hash链路进行二元数组化的一个链路存储
module Aio::Base::Toolkit
  class Chain

    def initialize
      @chain = []
    end

    # 分裂出多条key值数组
    def split(key, num)

      if @chain.empty?
        num.times { @chain.push [key.to_s] }

      else
        last = @chain.pop
        tmp = ::Array.new(num) { last.clone << key }
        @chain.concat tmp
        @chain
      end
    end

    # 获取一条链路
    def get_line
      @chain.pop
    end

    def empty?
      @chain.empty?
    end
  end

  # 将嵌套的Hash变成二元数组
  module Hash
    def self.flat_cm1(cm, chain, res)
      Hash.flat(cm, chain, res, :cm1)
    end

    def self.flat_cm2(cm, chain, res)
      Hash.flat(cm, chain, res, :cm2)
    end

    # 返回的是以StringConcat为元素的数组
    def self.flat(cm, chain, res, cm_type)
      cm.each_pair do |key, val|

        if val.kind_of? ::Hash
          chain.split(key, val.size)
          Aio::Base::Toolkit::Hash.flat(val, chain, res, cm_type)

        else

          last_chain = chain.get_line unless chain.empty?
          last_chain ||= []

          last_chain.push(key.to_s)
          last_chain.push(val)

          res << StringConcat.new(last_chain, cm_type)
        end
      end
    end

    # 建立一个结构体，方便包含cm的类型进行比较
    StringConcat = Struct.new(:line, :string, :cm_type) do
      def initialize(line, cm_type)
        super(
          line,
          long_name(line),
          cm_type
        )
      end

      def long_name(arr)
        res = ''
        arr.each { |x| res += x.to_s }
        res
      end

      # 判断与另一个StringConcat是否相等
      def eql?(other)
        self.string == other.string
      end

      def inspect
        self.line
      end

      def to_s
        self.string
      end
    end
  end
end

